package net.ufrog.common;

import net.ufrog.common.utils.Numbers;
import net.ufrog.common.utils.Strings;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 货币金额
 *
 * @author ultrafrog, ufrog.net@gmail.com
 * @version 0.1, 2016-04-05
 * @since 0.1
 */
public class Currency implements Serializable {

    private static final long serialVersionUID = 3766143383136238226L;

    /** 金额 */
    private BigDecimal amount;

    /** 舍位方式 */
    private RoundingMode roundingMode;

    /** 精度 */
    private Integer scale;

    /** 构造函数 */
    public Currency() {
        this(BigDecimal.ZERO);
    }

    /**
     * 构造函数
     *
     * @param amount 金额
     */
    public Currency(BigDecimal amount) {
        this(amount, RoundingMode.HALF_UP, 2);
    }

    /**
     * 构造函数
     *
     * @param amount 金额
     */
    public Currency(String amount) {
        this(new BigDecimal(amount));
    }

    /**
     * 构造函数
     *
     * @param amount 金额
     */
    public Currency(Double amount) {
        this(BigDecimal.valueOf(amount));
    }

    /**
     * 构造函数
     *
     * @param amount 金额
     * @param roundingMode 舍位方式
     * @param scale 精度
     */
    public Currency(BigDecimal amount, RoundingMode roundingMode, Integer scale) {
        this.amount = amount;
        this.roundingMode = roundingMode;
        this.scale = scale;
    }

    /**
     * 构造函数
     *
     * @param amount 金额
     * @param roundingMode 舍位方式
     * @param scale 精度
     */
    public Currency(String amount, RoundingMode roundingMode, Integer scale) {
        this(amount);
        this.roundingMode = roundingMode;
        this.scale = scale;
    }

    /**
     * 构造函数
     *
     * @param amount 金额
     * @param roundingMode 舍位方式
     * @param scale 精度
     */
    public Currency(Double amount, RoundingMode roundingMode, Integer scale) {
        this(amount);
        this.roundingMode = roundingMode;
        this.scale = scale;
    }

    /**
     * 加
     *
     * @param augend 被加数
     * @return 对象本身
     */
    public Currency add(BigDecimal augend) {
        amount = amount.add(augend);
        return this;
    }

    /**
     * 加
     *
     * @param augend 被加数
     * @return 对象本身
     */
    public Currency add(Integer augend) {
        return add(BigDecimal.valueOf(augend));
    }

    /**
     * 加
     *
     * @param augend 被加数
     * @return 对象本身
     */
    public Currency add(Long augend) {
        return add(BigDecimal.valueOf(augend));
    }

    /**
     * 加
     *
     * @param augend 被加数
     * @return 对象本身
     */
    public Currency add(Double augend) {
        return add(BigDecimal.valueOf(augend));
    }

    /**
     * 加
     *
     * @param augend 对象本身
     * @return 对象本身
     */
    public Currency add(String augend) {
        return add(new BigDecimal(augend));
    }

    /**
     * 减
     *
     * @param subtrahend 减数
     * @return 对象本身
     */
    public Currency subtract(BigDecimal subtrahend) {
        amount = amount.subtract(subtrahend);
        return this;
    }

    /**
     * 减
     *
     * @param subtrahend 减数
     * @return 对象本身
     */
    public Currency subtract(Integer subtrahend) {
        return subtract(BigDecimal.valueOf(subtrahend));
    }

    /**
     * 减
     *
     * @param subtrahend 减数
     * @return 对象本身
     */
    public Currency subtract(Long subtrahend) {
        return subtract(BigDecimal.valueOf(subtrahend));
    }

    /**
     * 减
     *
     * @param subtrahend 减数
     * @return 对象本身
     */
    public Currency subtract(Double subtrahend) {
        return subtract(BigDecimal.valueOf(subtrahend));
    }

    /**
     * 减
     *
     * @param subtrahend 减数
     * @return 对象本身
     */
    public Currency subtract(String subtrahend) {
        return subtract(new BigDecimal(subtrahend));
    }

    /**
     * 乘
     *
     * @param multiplicand 被乘数
     * @return 对象本身
     */
    public Currency multiply(BigDecimal multiplicand) {
        amount = amount.multiply(multiplicand);
        return this;
    }

    /**
     * 乘
     *
     * @param multiplicand 被乘数
     * @return 对象本身
     */
    public Currency multiply(Integer multiplicand) {
        return multiply(BigDecimal.valueOf(multiplicand));
    }

    /**
     * 乘
     *
     * @param multiplicand 被乘数
     * @return 对象本身
     */
    public Currency multiply(Long multiplicand) {
        return multiply(BigDecimal.valueOf(multiplicand));
    }

    /**
     * 乘
     *
     * @param multiplicand 被乘数
     * @return 对象本身
     */
    public Currency multiply(Double multiplicand) {
        return multiply(BigDecimal.valueOf(multiplicand));
    }

    /**
     * 乘
     *
     * @param multiplicand 被乘数
     * @return 对象本身
     */
    public Currency multiply(String multiplicand) {
        return multiply(new BigDecimal(multiplicand));
    }

    /**
     * 除
     *
     * @param divisor 除数
     * @return 对象本身
     */
    public Currency divide(BigDecimal divisor) {
        try {
            amount = amount.divide(divisor);
        } catch (ArithmeticException e) {
            amount = amount.divide(divisor, scale, roundingMode);
        }
        return this;
    }

    /**
     * 除
     *
     * @param divisor 除数
     * @return 对象本身
     */
    public Currency divide(Integer divisor) {
        return divide(BigDecimal.valueOf(divisor));
    }

    /**
     * 除
     *
     * @param divisor 除数
     * @return 对象本身
     */
    public Currency divide(Long divisor) {
        return divide(BigDecimal.valueOf(divisor));
    }

    /**
     * 除
     *
     * @param divisor 除数
     * @return 对象本身
     */
    public Currency divide(Double divisor) {
        return divide(BigDecimal.valueOf(divisor));
    }

    /**
     * 除
     *
     * @param divisor 除数
     * @return 对象本身
     */
    public Currency divide(String divisor) {
        return divide(new BigDecimal(divisor));
    }

    /**
     * 设置舍位方式
     *
     * @param roundingMode 舍位方式
     * @return 对象本身
     */
    public Currency setRoundingMode(RoundingMode roundingMode) {
        this.roundingMode = roundingMode;
        return this;
    }

    /**
     * 设置精度
     *
     * @param scale 精度
     * @return 对象本身
     */
    public Currency setScale(Integer scale) {
        this.scale = scale;
        return this;
    }

    /**
     * 读取金额
     *
     * @return 金额
     */
    public BigDecimal getAmount() {
        return amount;
    }

    /**
     * 读取舍位后金额
     *
     * @return 金额
     */
    public BigDecimal getRoundingAmount() {
        return amount.setScale(scale, roundingMode);
    }

    /**
     * 转换金额字符串
     *
     * @param prefix 前缀
     * @return 金额字符串
     */
    public String toCurrency(String prefix) {
        return (Strings.empty(prefix) ? "" : prefix) + Numbers.currency(getRoundingAmount());
    }

    @Override
    public String toString() {
        return getRoundingAmount().toPlainString();
    }
}
